﻿//+--------------------------------------------------------------------------------------------------
//
//Description: Windows Role Or Feature
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using VmroleAuthor.ViewModels;

namespace VmroleAuthor.Models
{
    public class RoleOrFeature
    {
        public Guid Id;
        public string Name;
        public OSFeatureDisplayNameEnum DisplayName;
        public OSFeatureType Type;
        public int NumericId;
        public OSFeatureCompatibleOS CompatibleOS;

        // Children
        public Dictionary<Guid, RoleOrFeature> Children;
    }


    public class WindowsRoleOrFeatures
    {
        public const string WindowsRolesAndFeaturesText = "WindowsRolesAndFeatures.txt";

        public bool ParsingError { get; private set; }

        // WindowsServer2008R2 Win7
        // WindowsServer2012  Win8
        // WindowsServer2012R2  Blue
        public Dictionary<OSFeatureCompatibleOS, Dictionary<Guid, RoleOrFeature>> Roles;
        public Dictionary<OSFeatureCompatibleOS, Dictionary<Guid, RoleOrFeature>> Features;

        private static WindowsRoleOrFeatures _rolesAndFeatures;
        private static readonly object LockObject = new object();


        public static WindowsRoleOrFeatures GetWindowsRoleOrFeatures()
        {
            lock (LockObject)
            {
                if (_rolesAndFeatures == null)
                {
                    _rolesAndFeatures = new WindowsRoleOrFeatures();
                    _rolesAndFeatures.ConstructRoleFeatureTreeFromFile();
                }
            }
            return _rolesAndFeatures;
        }
            
        private void ConstructRoleFeatureTreeFromFile()
        {
            this.Roles = new Dictionary<OSFeatureCompatibleOS, Dictionary<Guid, RoleOrFeature>>();
            this.Features = new Dictionary<OSFeatureCompatibleOS, Dictionary<Guid, RoleOrFeature>>();
            this.ParsingError = false;

            this.Roles.Add(OSFeatureCompatibleOS.WindowsServer2008R2, new Dictionary<Guid, RoleOrFeature>());
            this.Features.Add(OSFeatureCompatibleOS.WindowsServer2008R2, new Dictionary<Guid, RoleOrFeature>());
            this.Roles.Add(OSFeatureCompatibleOS.WindowsServer2012, new Dictionary<Guid, RoleOrFeature>());
            this.Features.Add(OSFeatureCompatibleOS.WindowsServer2012, new Dictionary<Guid, RoleOrFeature>());
            this.Roles.Add(OSFeatureCompatibleOS.WindowsServer2012R2, new Dictionary<Guid, RoleOrFeature>());
            this.Features.Add(OSFeatureCompatibleOS.WindowsServer2012R2, new Dictionary<Guid, RoleOrFeature>());

            try
            {
                  if (System.IO.File.Exists(WindowsRolesAndFeaturesText))
                  {
                     using (StreamReader file = System.IO.File.OpenText(WindowsRolesAndFeaturesText))
                     {
                         string line;
                         while ((line = file.ReadLine()) != null)
                         {                            
                             string[] sections = line.Split(new[] {','});
                             if (sections.Length == 7)
                             {
                                OSFeatureType roleOrFeature = (OSFeatureType)Enum.Parse(typeof(OSFeatureType), sections[3]);
                                OSFeatureCompatibleOS compatibleOS = (OSFeatureCompatibleOS) Enum.Parse(typeof (OSFeatureCompatibleOS), sections[6]);
                                Dictionary<Guid, RoleOrFeature> dict = (roleOrFeature == OSFeatureType.Feature)
                                    ? this.Features[compatibleOS] : this.Roles[compatibleOS];                                

                                 RoleOrFeature osRoleFeature  = new RoleOrFeature();
                                 string id = sections[0].Trim().Trim('\'');
                                 osRoleFeature.Id = Guid.Parse(id);
                                 osRoleFeature.DisplayName = (OSFeatureDisplayNameEnum)Enum.Parse(typeof(OSFeatureDisplayNameEnum), sections[1]);
                                 osRoleFeature.Name = sections[2].Trim().Trim('\'');
                                 osRoleFeature.Type = roleOrFeature;
                                 osRoleFeature.NumericId = int.Parse(sections[5]);
                                 osRoleFeature.CompatibleOS = compatibleOS;
                                 osRoleFeature.Children = new Dictionary<Guid, RoleOrFeature>();
                                 Guid? parentId = null;                                 
                                 if (sections[4] != null && !sections[4].Contains("NULL"))
                                 {
                                     parentId = Guid.Parse(sections[4].Trim().Trim('\''));
                                 }
                                 RoleOrFeature parent =  FindParent(parentId, dict);                                                  
                                 if (parent == null)
                                 {
                                     //This is the root child
                                     dict.Add(osRoleFeature.Id, osRoleFeature);
                                 }
                                 else
                                 {
                                     parent.Children.Add(osRoleFeature.Id, osRoleFeature);
                                 }
                             }
                         }
                     }
                  }
            }
            //ArgumentException
            catch (Exception ex )
            {
                MessageBox.Show("Parsing Error while initializing the list of roles and features from " + WindowsRolesAndFeaturesText + " " + ex.Message, DefinitionViewModel.ToolHeader);
                this.ParsingError = true;
            }
        }


        private static RoleOrFeature FindParent(Guid? parentId, Dictionary<Guid, RoleOrFeature> dictionary)
        {
            if (parentId == null)
            {
                return null;
            }
            if (dictionary.ContainsKey(parentId.Value))
            {
                return dictionary[parentId.Value];
            }
            foreach (KeyValuePair<Guid, RoleOrFeature> roleOrFeature in dictionary)
            {
                if (roleOrFeature.Value.Children.Count > 0)
                {
                    RoleOrFeature parent = FindParent(parentId, roleOrFeature.Value.Children);
                    if (parent != null)
                    {
                        return parent;
                    }
                }
            }            
            return null;
        }




    }
}
